package evs.identification;

import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import evs.brp.Marshaller;
import evs.brp.Message;
import evs.brp.RemotingErrorException;

public class NameServerInvoker extends evs.brp.Invoker {
	
	private Log log = LogFactory.getLog(NameServerInvoker.class);
	
	private Class clazz;
	private Object methodObject; 
	
	private static final String LOOKUPCLASS = "evs.identification.NameServerLookup";
	
	/**
	 * constructor for static instances
	 * (empty constructor for non-static instances, like in evs.brp.invoker)
	 */
	public NameServerInvoker() throws RemotingErrorException {
		log.info("creating static LookUp instance");
		try {
			clazz = Class.forName(LOOKUPCLASS);
			methodObject = clazz.newInstance();
		}
		catch (Exception exc) {
			throw new RemotingErrorException(exc);
		}	
	}
	
	/**
	 * one to one copy of evs.brp.invoker.delegate
	 * except: above constructor lines were outsourced
	 */
	@Override
	public void delegate(ObjectInput objectInput, ObjectOutput objectOutput) throws RemotingErrorException {
		log.info("streams arrived. delegate 'em...");
		
		try {
			/*
			 * demarshalling object input
			 */
			Message message = Marshaller.demarshall(objectInput);
			
			/*
			 * remote object method invoke via reflection
			 */			
            Class argClazzes[] = new Class[message.getArgumentclazzes().size()];
            for (int i=0; i < message.getArgumentclazzes().size(); i++) {
            	argClazzes[i] = message.getArgumentclazzes().get(i);
            }

			log.info("doing method invocation via reflection");
			Method method = clazz.getMethod(message.getMethodName(), argClazzes);
			
			Object returnObject = null;
			
			try {
				
				returnObject = method.invoke(methodObject, message.getArguments().toArray());
				
			} catch (Exception exc) {
				
				RemotingErrorException re = new RemotingErrorException(exc);
				
				/**
				 * remote object call raised exception -> transport in message
				 */
				Message returnMessage = new Message();
				returnMessage.setException(re);
				
				Marshaller.marshall(objectOutput, returnMessage);
				objectOutput.flush();
				
				log.info("exception occured - message written back");
				
				throw re;
				
			}
				
			log.info("try to write back");
			
			/*
			 * marshalling return value of method
			 */
			Message returnMessage = new Message();
			returnMessage.setReturnClazz(message.getReturnClazz());
			returnMessage.setReturnValue(message.getReturnClazz().cast(returnObject));
				
			Marshaller.marshall(objectOutput, returnMessage);
			
			objectOutput.flush();
				
			log.info("message written back");			

		} 
		catch (RemotingErrorException re) {
			throw re;
		} 
		catch (Exception exc) {
			throw new RemotingErrorException(exc);
		}		
	}

}
